package fem2d;

import java.util.ArrayList;

import fem2.AbstractStructuralStaticDemo;
import fem2.Constraint;
import fem2.Debugger;
import fem2.Element;
import fem2.MaterialModel;
import fem2.Mesh;
import fem2.MeshGenerator;
import fem2.MeshPart;
import fem2.MeshUtilities;
import fem2.Model;
import fem2.Node;
import fem2.Observer;
import fem2.analysis.Analysis;
import fem2.analysis.NonlinearStaticAnalysis;
import fem2.element.StructuralElement;
import fem2.enu.EchoLevelType;
import fem2.enu.State;
import fem2.material.FluencyCriteria;
import fem2.material.LemaitreDamageMM2;
import fem2.observer.GidDamageObserver;
import fem2.observer.TimeStepObserver;
import fem2.pre_and_post.GidMeshGenerator;
import fem2.strategies.Strategy;

/**
 * demo as example 12.4.3 in Souza Neto book
 * 
 * @author hbui
 * 
 */
public class CylindricalNotchedBar extends AbstractStructuralStaticDemo {

	public CylindricalNotchedBar() {
		projectDir = "/home/hbui/kratos_janosch";
		projectName = "cylindrical-notched-bar.gid";
		meshFileName = "mesh1.msh";
	}

	@Override
	public Mesh createMesh() {
		String fn = projectDir + '/' + projectName + '/' + meshFileName;
		MeshGenerator mg = new GidMeshGenerator(fn);
		Mesh mesh = mg.getMesh(2);
		return mesh;
	}

	@Override
	public Model createConditions(Model m) {
		Mesh mesh = m.getMesh();

		// double du = 0.576;
		// double du = 0.5;
		double du = 1;

		Constraint cx = new Constraint(false, true);
		Constraint cy = new Constraint(true, false);
		Constraint cu = new Constraint(true, false);

		cu.setValue(1, du);

		ArrayList<Node> left_edge = MeshUtilities.seekNodesOnSurface(mesh, 1, 0, 0);
		ArrayList<Node> bottom_edge = MeshUtilities.seekNodesOnSurface(mesh, 0, 1, 0);
		ArrayList<Node> top_edge = MeshUtilities.seekNodesOnSurface(mesh, 0, 1, -20);

		mesh.addConstraint(cx, left_edge);
		mesh.addConstraint(cy, bottom_edge);
		mesh.addConstraint(cu, top_edge);

		return m;
	}

	@Override
	public MaterialModel createMaterial(Model m) {
		double E = 210e3;
		double nu = 0.3;
		double t = 1.0;
		double r = 3.5;
		double s = 1.0;

		FluencyCriteria isotropicHardeningRule = new FluencyCriteria() {

			@Override
			public double computeFluencyValue(double v) {
				return 620 + 3300 * (1 - Math.exp(-0.4 * v));
			}

			@Override
			public double computeFluencyDerivative(double v) {
				return 3300 * 0.4 * Math.exp(-0.4 * v);
			}
		};

		return new LemaitreDamageMM2(E, nu, t, 0, State.PLANE_STRAIN, isotropicHardeningRule, r, s);

		// return new StVenantKirchhoffMM(E, nu, t, 0, State.PLANE_STRAIN);

		// FluencyCriteria kinematicHardeningRule = new
		// LinearKinematicHardeningRule(0);
		// return new VonMisesMM(E, nu, t, 0, State.PLANE_STRAIN,
		// isotropicHardeningRule,
		// kinematicHardeningRule);
	}

	@Override
	public Element createElement(MeshPart mp, MaterialModel mm) {
		StructuralElement e = new StructuralElement(mp, mm);
		// e.setIntegrationType(IntegrationType.REDUCED_INTEGRATION);
		return e;
	}

	@Override
	public void addObservers(Model m, Strategy s, TimeStepObserver o) {
		super.addObservers(m, s, o);

		if (meshFileName == null) {
			throw new Error("mesh file name was not set");
		}

		/*
		 * clean all previous post files
		 */
		String meshName = meshFileName.split("\\.")[0];

		Observer do1 = new GidDamageObserver(m, o, projectDir, projectName, meshName);
		s.addObserver(do1);

	}

	@Override
	public void run(int nt) {
		Model m = createModel();

		Analysis an = new NonlinearStaticAnalysis(m, nt);
		Strategy s = an.getStrategy();
		s.setEchoLevel(EchoLevelType.OUTPUT, EchoLevelType.AUX1, EchoLevelType.AUX5);
		// ((NewtonRaphsonStrategy) s)
		// .setLineSearchCriteria(LineSearchCriteria.INTERPOLATED_LINE_SEARCH);

		addObservers(m, s, new TimeStepObserver(s));

		an.run();

		// postProcess(m);

		Debugger.warn("Analysis completed");
	}

	public static void main(String[] args) {
		AbstractStructuralStaticDemo demo = new CylindricalNotchedBar();

		// demo.run(10);
		// demo.run(60);
		demo.run(100);
	}
}
